#!/bin/bash

################################
# this module defines some action about docker proxy
# NOTE: this is a partial module of dfproxym
###############################

docker_config_path=/etc/docker
daemon_json="${docker_config_path}"/daemon.json

docker_usage() {
  echo "Kind:  docker"
  echo "  e.g. $prog docker                              note: show docker subcommand usage"
  echo "       $prog docker status                        note: show status of docker proxy"
  echo "       $prog docker update [keyword]             note: update proxy config using api with optional keyword filter"
  echo "       $prog docker pull <image>                 note: pull image from proxy"
}

get_docker_all_registry_mirrors() {
  if [ -f "${daemon_json}" ]; then
    cat "${daemon_json}" | jq -r '."registry-mirrors"[]?'
  else
    echo ""
  fi
}

###############################
# @param keyword: keyword of mirror
# @return mirror: mirror name of target mirror
###############################
get_docker_mirror() {
  local keyword=${1:-""}
  local check=0
  local num=0
  mirror=""

  check=$(get_docker_all_registry_mirrors | grep "${keyword}")
  if [ -z "$check" ]; then _err "no available operating object" "$keyword"; fi
  num=$(get_docker_all_registry_mirrors | grep -c "${keyword}")

  if [ "${num}" -eq 1 ]; then
    mirror=$(get_docker_all_registry_mirrors | grep "${keyword}")
  else
    # here need output to stderr, for user may use less command or similar
    >&2 echo "====================================================================="
    local line_num=0
    for line in $(get_docker_all_registry_mirrors | grep "${keyword}"); do
      ((line_num++)) || true
      printf "%2d-> %s\n" ${line_num} "${line}" | grep --color "${keyword}" 1>&2
    done

    >&2 echo "====================================================================="
    >&2 echo -n "which do you want to execute, please input front line num... "
    read -r lnum
    if [[ ${lnum} -lt 1 || ${lnum} -gt ${num} ]]; then
      _err "invalid input line num, please checkout~"
    fi

    mirror=$(get_docker_all_registry_mirrors | grep "${keyword}" | awk '{print $1}' | awk -v ln="${lnum}" 'NR==ln {print}')
  fi
}

###############################
# @return docker_proxy_list_api_response
# @return docker_proxy_extract_result
# #############################
get_selectable_docker_proxy_list() {
  [[ ! -z "${CFG[docker.api_cmd]}" ]] || _err "api_cmd is empty, please set in config"
  [[ ! -z "${CFG[docker.extract_cmd]}" ]] || _err "extract_cmd is empty, please set in config"
  local show_response=${CFG[docker.api_show_response]:-"0"}
  _info "${CFG[docker.api_cmd]}"
  docker_proxy_list_api_response=$(eval "${CFG[docker.api_cmd]}")
  [[ "${show_response}" -eq 1 ]] && echo "API Response: $docker_proxy_list_api_response"
  docker_proxy_extract_result=$(echo "$docker_proxy_list_api_response" | eval "${CFG[docker.extract_cmd]}")
}

###############################
# @keyword
# @return selected_docker_proxy_url
# @return selected_docker_proxy_prefix
###############################
select_docker_proxy() {
  local keyword=${1:-""}
  local check=0
  local num=0
  selected_docker_proxy_url=""
  selected_docker_proxy_prefix=""
  get_selectable_docker_proxy_list
  
  if [[ -n "$keyword" ]]; then
    check=$(echo "${docker_proxy_extract_result}" | grep "${keyword}" || true)
  else
    check="${docker_proxy_extract_result}"
  fi
  
  if [[ -z "$check" ]]; then
    _err "no available operating object matching: ${keyword}"
  fi
  
  num=$(echo "${check}" | wc -l)

  if [[ "${num}" -eq 1 ]]; then
    selected_docker_proxy_url=$(echo "${check}" | head -1)
  else
    # 显示选择菜单
    >&2 echo "====================================================================="
    >&2 echo "Available Docker proxies:"
    local line_num=0
    local -a proxy_list
    mapfile -t proxy_list < <(echo "${check}")
    
    for line in "${proxy_list[@]}"; do
      ((line_num++)) || true
      printf "%2d-> %s\n" ${line_num} "${line}" 1>&2
    done

    >&2 echo "====================================================================="
    >&2 echo -n "Please select a proxy (1-${num}): "
    read -r lnum
    
    if [[ ${lnum} -lt 1 || ${lnum} -gt ${num} ]]; then
      _err "Invalid selection, please choose between 1 and ${num}"
    fi

    selected_docker_proxy_url="${proxy_list[$((lnum-1))]}"
  fi
  
  selected_docker_proxy_prefix="${selected_docker_proxy_url}"
  selected_docker_proxy_prefix="${selected_docker_proxy_prefix#*://}"
  selected_docker_proxy_prefix="${selected_docker_proxy_prefix%/}"
  
  _info "Selected proxy: ${selected_docker_proxy_url}"
  _info "Proxy prefix: ${selected_docker_proxy_prefix}"
}

show_docker_status() {
  local prefix_config_status=""
  local prefix_search_result=""
  local mirror_config_status=""

  get_selectable_docker_proxy_list

  prefix_config_status=$([[ -z "${CFG[docker.proxy_prefix]}" ]] && echo "Disable" || echo "Enable")

  echo "=== docker proxy status ==="
  echo "docker prefix proxy: ${prefix_config_status} => ${CFG[docker.proxy_prefix]}"
  echo ""
  echo "docker porxy api call: "
  echo "${docker_proxy_list_api_response}"
  echo ""
  # echo "docker mirror proxy: ${mirror_config_status}"
}

###############################
# Update Docker daemon configuration with registry mirrors
# This function modifies /etc/docker/daemon.json
###############################
update_docker_daemon_config() {
  local mirror_url="${CFG[docker.mirror_url]:-""}"
  
  if [[ -z "$mirror_url" ]]; then
    _warn "No mirror URL configured, skipping Docker daemon update"
    return 0
  fi
  
  # 检查是否有权限修改docker配置
  if [[ ! -w "${docker_config_path}" ]]; then
    _warn "No write permission to ${docker_config_path}, Docker daemon config update skipped"
    _warn "Please run with sudo or manually update ${daemon_json}"
    return 0
  fi
  
  # 创建docker配置目录
  sudo mkdir -p "${docker_config_path}"
  
  # 读取或创建daemon.json
  local current_daemon_config
  if [[ -f "${daemon_json}" ]]; then
    current_daemon_config=$(cat "${daemon_json}")
  else
    current_daemon_config='{}'
  fi
  
  # 更新registry mirrors配置
  local updated_config
  updated_config=$(echo "$current_daemon_config" | jq --arg mirror "$mirror_url" '
    ."registry-mirrors" = ["registry.docker-cn.com", "hub-mirror.c.163.com"]
  ')
  
  # 写入新配置
  echo "$updated_config" | sudo tee "${daemon_json}" > /dev/null
  
  if [[ $? -eq 0 ]]; then
    _info "Docker daemon configuration updated successfully"
    _info "Please restart Docker service for changes to take effect"
    echo "  sudo systemctl restart docker"
  else
    _err "Failed to update Docker daemon configuration"
  fi
}

# << docker-proxy
# pulling docker image from specific proxy
# @param proxy_prefix: default "", the prefix of docker iamge proxy
# @param retag_proxy_image: default "1", if retag proxy image by removing proxy prefix after pulling image from proxy
# @param keep_proxy_image: default "0", if keep proxy image after pulling image from proxy
# @param input args
execute_dockerpp() {

  local proxy_prefix=${1:-""}
  local retag_proxy_image=${2:-"1"}
  local keep_proxy_image=${3:-"0"}
  local args=${@:4}
  local new_args=()
  local origin_image=""

  for arg in "${args}"; do
    if [[ $arg != -* ]]; then
      new_args+=("${proxy_prefix}/$arg")
      origin_image="$arg"
    else
      new_args+=("$arg")
    fi
  done

  echo "docker pull ${new_args}"
  docker pull "${new_args}"

  local res="$?"
  if [[ "$res" -ne 0 ]]; then
    return $res
  fi

  if [[ "${retag_proxy_image}" -eq 1 ]]; then
    docker tag "${proxy_prefix}/${origin_image}" "${origin_image}"
    if [[ "${keep_proxy_image}" -eq 0 ]]; then
      docker rmi "${proxy_prefix}/${origin_image}"
    fi
  fi
}
# >> docker-proxy

update_docker_proxy_config_by_api() {
  local keyword=${1:-""}
  select_docker_proxy "${keyword}"
  [[ ! -z "${selected_docker_proxy_url}" ]] || _err "cannot select docker proxy url"
  [[ ! -z "${selected_docker_proxy_prefix}" ]] || _err "cannot select docker proxy prefix"

  # 更新配置文件中的代理配置
  _info "Updating docker proxy configuration..."
  
  # 创建临时配置文件
  local temp_config
  temp_config=$(mktemp)
  
  # 读取当前配置并更新
  if [[ -f "${proxy_config_path}" ]]; then
    strip_jsonc "${proxy_config_path}" | jq --arg prefix "${selected_docker_proxy_prefix}" \
      --arg mirror_url "${selected_docker_proxy_url}" \
      '.docker.proxy_prefix = $prefix | .docker.mirror_url = $mirror_url' > "${temp_config}"
  else
    get_default_json_config | jq --arg prefix "${selected_docker_proxy_prefix}" \
      --arg mirror_url "${selected_docker_proxy_url}" \
      '.docker.proxy_prefix = $prefix | .docker.mirror_url = $mirror_url' > "${temp_config}"
  fi
  
  # 备份原配置并应用新配置
  if [[ -f "${proxy_config_path}" ]]; then
    cp "${proxy_config_path}" "${proxy_config_path}.bak"
    _info "Backup created: ${proxy_config_path}.bak"
  fi
  
  cp "${temp_config}" "${proxy_config_path}"
  rm "${temp_config}"
  
  # 更新Docker daemon配置
  update_docker_daemon_config
  
  _info "Docker proxy configuration updated successfully"
  _info "Proxy prefix: ${selected_docker_proxy_prefix}"
  _info "Mirror URL: ${selected_docker_proxy_url}"
}

execute_docker_proxy_pull() {
  local proxy_prefix=${CFG[docker.proxy_prefix]:-""}
  if [ -z "$proxy_prefix" ]; then
    _err "docker.proxy_prefix is empty, please update by '$prog config edit'"
  fi

  local retag_proxy_image=${CFG[docker.retag_after_pull_from_proxy]:-"1"}
  local keep_proxy_image=${CFG[docker.keep_proxy_tag]:-"0"}

  execute_dockerpp "${proxy_prefix}" "${retag_proxy_image}" "${keep_proxy_image}" "$@"
}

execute_subcmd_docker() {
  local cmd=${1:-""}
  local args=${@:2}

  case "${cmd}" in
  status)
    check_config_if_exist
    load_configs
    show_docker_status
    ;;
  update)
    check_config_if_exist
    load_configs
    update_docker_proxy_config_by_api "${args}"
    ;;
  pull)
    check_config_if_exist
    load_configs
    execute_docker_proxy_pull "${args}"
    ;;
  *)
    docker_usage
    _err "unknown subcmd of docker: ${cmd}"
    ;;
  esac

}
